<?php
/**
 * Leek - Zend Framework Components
 *
 * @category   Leek
 * @package    Leek_Application
 * @subpackage Resource
 * @author     Chris Jones <leeked@gmail.com>
 * @link       http://code.google.com/p/leek-zf-components/
 * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
 * @version    $Id: Cache.php 78 2009-11-03 23:37:56Z leeked $
 */

/**
 * Resource for setting up Zend_Cache
 *
 * @uses       Zend_Application_Resource_ResourceAbstract
 * @category   Leek
 * @package    Leek_Application
 * @subpackage Resource
 * @author     Chris Jones <leeked@gmail.com>
 * @link       http://code.google.com/p/leek-zf-components/
 * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
 */
class Leek_Application_Resource_Cache extends Zend_Application_Resource_ResourceAbstract
{
    /**
     * Cache object
     *
     * @var Zend_Cache_Core
     */
    protected $_cache;

    /**
     * Frontend to use
     *
     * @var string
     */
    protected $_frontend = null;

    /**
     * Frontend options
     *
     * @var array
     */
    protected $_frontendOptions = array();

    /**
     * Backend to use
     *
     * @var string
     */
    protected $_backend = null;

    /**
     * Backend options
     *
     * @var array
     */
    protected $_backendOptions = array();

    /**
     * Wether to register the created cache as default metadata cache
     *
     * @var boolean
     */
    protected $_isDefaultMetadataCache = false;

    /**
     * Set the Frontend
     *
     * @param  string $frontend
     * @return Leek_Application_Resource_Cache
     */
    public function setFrontend($frontend)
    {
        $this->_frontend = $frontend;
        return $this;
    }

    /**
     * Frontend to use
     *
     * @return string
     */
    public function getFrontend()
    {
        return $this->_frontend;
    }

    /**
     * Set the Frontend options
     *
     * @param  array $frontendOptions
     * @return Leek_Application_Resource_Cache
     */
    public function setFrontendOptions($frontendOptions)
    {
        if ($this->getFrontend() == 'Page') {
            $frontendOptions = $this->_fixRegexps($frontendOptions);
        }

        if ($this->getFrontend() == 'File') {
            $frontendOptions = $this->_fixMasterFiles($frontendOptions);
        }

        $this->_frontendOptions = $frontendOptions;
        return $this;
    }

    /**
     * Frontend options to use
     *
     * @return array
     */
    public function getFrontendOptions()
    {
        return $this->_frontendOptions;
    }

    /**
     * Set the Backend
     *
     * @param  string $frontend
     * @return Leek_Application_Resource_Cache
     */
    public function setBackend($backend)
    {
        $this->_backend = $backend;
        return $this;
    }

    /**
     * Backend to use
     *
     * @return string
     */
    public function getBackend()
    {
        return $this->_backend;
    }

    /**
     * Set the Backend options
     *
     * @param  array $backendOptions
     * @return Leek_Application_Resource_Cache
     */
    public function setBackendOptions($backendOptions)
    {
        $this->_backendOptions = $this->_removeNulls($backendOptions);
        return $this;
    }

    /**
     * Backend options to use
     *
     * @return array
     */
    public function getBackendOptions()
    {
        return $this->_backendOptions;
    }

    /**
     * Set whether to use this as default metadata cache
     *
     * @param  boolean $isDefaultMetadataCache
     * @return Leek_Application_Resource_Cache
     */
    public function setisDefaultMetadataCache($isDefaultMetadataCache)
    {
        $isDefaultMetadataCache = $isDefaultMetadataCache == 'false' ? false : $isDefaultMetadataCache;
        $this->_isDefaultMetadataCache = (bool) $isDefaultMetadataCache;
        return $this;
    }

    /**
     * Use this as the default metadata cache?
     *
     * @return void
     */
    public function isDefaultMetadataCache()
    {
        return $this->_isDefaultMetadataCache;
    }

    /**
     * Sets the cache object
     *
     * @param Zend_Cache_Core $cache
     * @return Leek_Application_Resource_Cache
     */
    public function setCacheObject(Zend_Cache_Core $cache)
    {
        $this->_cache = $cache;
        return $this;
    }

    /**
     * Returns the cache object
     *
     * @return Zend_Cache_Core|null
     */
    public function getCacheObject()
    {
        return $this->_cache;
    }

    /**
     * Defined by Zend_Application_Resource_Resource
     *
     * @uses   Zend_Cache
     * @uses   Zend_Db_Table_Abstract
     * @return Zend_Cache_Core
     */
    public function init()
    {
        $cache = Zend_Cache::factory(
            $this->getFrontend(),
            $this->getBackend(),
            $this->getFrontendOptions(),
            $this->getBackendOptions()
        );

        if ($this->isDefaultMetadataCache()) {
            Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
        }

        if ($cache instanceOf Zend_Cache_Frontend_Page) {
            $cache->start();
        }

        $this->setCacheObject($cache);
        return $this->getCacheObject();
    }

    /**
     * Recursive function to remove empty strings from an array.
     * Empty values cause problems with Zend_Cache.
     *
     * @param array $array
     * @return array
     */
    private function _removeNulls(array $array)
    {
        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $array[$key] = $this->_removeNulls($value);
            } else {
                if (empty($value)) {
                    unset($array[$key]);
                }
            }
        }

        return $array;
    }

    /**
     * Fixes Regexps options if using an XML config.
     *
     * @param array $frontendOptions
     * @return array
     */
    private function _fixRegexps($frontendOptions)
    {
        if (isset($frontendOptions['regexps']) && !empty($frontendOptions['regexps'])) {

            // Try to discover if were using an XML style config
            // XML config doesn't exactly work with this style
            $xmlConfig = false;

            foreach ($frontendOptions['regexps'] as $key => $value) {
                foreach ($value as $regexKey => $regexValue) {
                    if (isset($regexValue['regex'])) {
                        $xmlConfig = true;
                    }
                    break 2;
                }
            }

            // If we are using an XML config, convert it to how we need it
            if ($xmlConfig) {

                $regexps = array();
                foreach ($frontendOptions['regexps'] as $key => $value) {
                    $regexKey     = isset($value['regex'])   ? $value['regex']   : false;
                    $regexOptions = isset($value['options']) ? $value['options'] : array();
                    if ($regexKey) {
                        $regexps[$regexKey] = $regexOptions;
                    }
                }

                $frontendOptions['regexps'] = $regexps;

            }

        }

        return $frontendOptions;
    }

    /**
     * Fixes Master Files options if using an XML config.
     *
     * @param array $frontendOptions
     * @return array
     */
    public function _fixMasterFiles($frontendOptions)
    {
        if (isset($frontendOptions['master_files']) && !empty($frontendOptions['master_files'])) {

            $masterFiles = array();
            foreach ($frontendOptions['master_files'] as $key => $value) {
                if (is_string($key)) {
                    $masterFiles[] = $value;
                } else {
                    $masterFiles = $frontendOptions['master_files'];
                    break;
                }
            }

            $frontendOptions['master_files'] = $masterFiles;

        }

        return $frontendOptions;
    }
}
